import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sound/public/flutter_sound_player.dart';
import 'package:im_app/im/util/DateUtil.dart';
import 'package:im_app/im/util/DbUtil.dart';
import 'package:im_app/im/util/ImConstant.dart';
import 'package:im_app/im/util/UiUtil.dart';
import 'dart:math' as math;

import '../../../../dao/ImCollectDao.dart';
import '../../../../dao/ImMessageDao.dart';
import '../../../../dao/ImSessionDao.dart';
import '../../../../pojo/ImPojo.dart';
import '../../../../service/ImCollectService.dart';
import '../../../../socket/dto/base/Resp.dart';
import '../../../../socket/dto/business/Message.dart';
import '../../../../socket/dto/business/PullData2.dart';
import '../../../../socket/dto/business/SendData.dart';
import '../../../../socket/service/RpcSendDataService.dart';
import '../../../../util/ImRichTextUtil.dart';
import '../../../../util/ImSingleton.dart';
import '../../../../util/LoggerUtil.dart';
import '../../../../util/MessageUtil.dart';


class ImMessageHandler {

  final _logger = createLogger();

  Future<bool> checkCollectMessages(List<ImMessage> messages) async {
    var userId = ImSingleton.getInstance().session.userId!;
    var collectDao = ImCollectDao();
    for (var message in messages) {
      var imSession = message.imSession;
      if (imSession == null) {
        var sessionDao = ImSessionDao();
        imSession = (await sessionDao.getById(message.sessionId!))!;
        message.imSession = imSession!;
      }
      var dbCollect = await collectDao.getByKey(userId, message.imSession?.serverId??'', message.serverId??'');
      if (dbCollect != null) {
        return true;
      }
    }
    return false;
  }

  // 收藏多个消息
  Future<bool> collectMessages(List<ImMessage> messages) async {
    var userId = ImSingleton.getInstance().session.userId!;

    var collectService = ImCollectService();
    var collectDao = ImCollectDao();

    var collects = <ImCollect>[];
    for(var message in messages) {
      var imSession = message.imSession;
      if (imSession == null) {
        var sessionDao = ImSessionDao();
        imSession = (await sessionDao.getById(message.sessionId!))!;
        message.imSession = imSession!;
      }

      var dbCollect = await collectDao.getByKey(userId, imSession.serverId!, message.serverId!);
      if (dbCollect != null) { // 已经收藏
        continue;
      }

      var collect = collectService.buildCollectFromMessage(userId, message);

      collects.add(collect);
    }

    if (collects.isEmpty) return false;

    var okListResp = await _sendCollectData(collects);

    _callbackCollectServerId(okListResp.localSeqSet, collects);

    await collectDao.batchInserts(collects);

    return true;
  }

  // 删除收藏
  Future<void> deleteCollect(ImCollect collect) async {
    var rpcBaseService = RpcBaseService();


    if (collect.serverId == null) {
      return;
    }
    var delReq = DelReq(serverId: collect.serverId!);
    await rpcBaseService.deleteCollect(delReq);

    var collectDao = ImCollectDao();
    await collectDao.delete(collect);
  }

  // 消息删除
  Future<void> deleteMessages(List<ImMessage> messages) async {
    if (messages.isEmpty) return;
    var canServerDeletesMessages = messages.where((m)=>m.serverId != null && m.serverId != '').toList(growable: false);
    var localDeletesMessages = messages.where((m)=>m.serverId == null || m.serverId == '').toList(growable: false);

    var rpcMessageService = RpcMessageService();
    var messageDao = ImMessageDao();

    if (canServerDeletesMessages.isNotEmpty) {
      for (var message in canServerDeletesMessages) {
        message.status = ImMessageStatus.delete;
        message.actionStatus = ImMessageActionStatus.delete;
        message.updateTime = DateTime.now();
      }
      await messageDao.batchChangeMessageStatus(canServerDeletesMessages);

      var serverIds = canServerDeletesMessages.map((m)=>m.serverId!).toList(growable: false);

      var deleteReq = MessageDeleteReq(messageIds: serverIds);
      var okReq = await rpcMessageService.sendDeleteMessages(deleteReq);

      for (var message in canServerDeletesMessages) {
        message.status = ImMessageStatus.delete;
        message.actionStatus = ImMessageActionStatus.deleted;
        message.updateTime = DateTime.now();
      }
      await messageDao.batchChangeMessageStatus(canServerDeletesMessages);
    }

    if (localDeletesMessages.isNotEmpty) {
      for (var message in localDeletesMessages) {
        message.status = ImMessageStatus.delete;
        message.actionStatus = ImMessageActionStatus.deleted;
        message.updateTime = DateTime.now();
      }
      await messageDao.batchChangeMessageStatus(localDeletesMessages);
    }

    UiUtil.uiDeleteMessages(messages);
  }

  // 消息撤回
  Future<void> withdrawMessage(ImMessage message) async {
    if (!DateUtil.hasExceededTime(message.serverReceiveTime??message.createTime, 2)) return;
    if (message.serverId == null) return;

    var messageDao = ImMessageDao();

    var rpcMessageService = RpcMessageService();
    await messageDao.updateMessageStatus(message.id!, ImMessageStatus.withdraw, ImMessageActionStatus.withdraw);
    var withdrawReq = MessageWithdrawReq(messageIds: [message.serverId!]);
    var okReq = await rpcMessageService.sendWithdrawMessages(withdrawReq);

    await messageDao.updateMessageStatus(message.id!, ImMessageStatus.withdrawed, ImMessageActionStatus.withdrawed);

    await messageDao.updateMessageStatus(message.id!, ImMessageStatus.withdrawed, ImMessageActionStatus.withdrawed);

    UiUtil.uiDeleteMessages([message]);
  }

  copyMessage(BuildContext context, ImMessage message, TextSelectionDelegate delegate) {
    final TextSelection selection = delegate.textEditingValue.selection;
    final int lastSelectionIndex = math.max(selection.baseOffset, selection.extentOffset);

    var text = message.content??'';
    if (lastSelectionIndex <= 1 || selection.baseOffset == selection.extentOffset) {
      Clipboard.setData(ClipboardData(text: text));
      delegate.hideToolbar();
      UiUtil.showSnackBar(context, '消息复制成功');
      return;
    }
    List<Object> spans = ImRichTextUtil.splitEmojis(text);
    List<Object> selectSpans = ImRichTextUtil.getSelectSpan(spans, selection.baseOffset, lastSelectionIndex);
    var copyStr = ImRichTextUtil.emojisToString(selectSpans);
    Clipboard.setData(ClipboardData(text: copyStr));
    delegate.hideToolbar();
    _cleanSelection(delegate);
    UiUtil.showSnackBar(context, '消息复制成功');
  }

  // 播放语音
  playAudio(BuildContext context, ImMessage message) async {
    _logger.i('[audio play start]', time: DateTime.now());
    try {
      var filePath = MessageUtil.getFilePath2(message);
      FlutterSoundPlayer? mPlayer = FlutterSoundPlayer();
      await mPlayer.openPlayer();
      mPlayer.startPlayer(fromURI: filePath, whenFinished: () async {
        await mPlayer.closePlayer();
      });
    } catch(error, stacktrace) {
      _logger.e("[audio play error]", error: error, stackTrace: stacktrace, time: DateTime.now());
    }
  }

  // 语音转文字
  transferAudioToText(BuildContext context, ImMessage message) {

  }

  _cleanSelection(TextSelectionDelegate delegate) {
    delegate.userUpdateTextEditingValue(
      delegate.textEditingValue.copyWith(
        selection: const TextSelection(baseOffset: 0, extentOffset: 0),
      ),
      SelectionChangedCause.toolbar,
    );
  }

  // 发送收藏数据
  Future<OkListResp> _sendCollectData(List<ImCollect> collects) async {
    var rpcBaseService = RpcBaseService();
    List<CollectInfoItem> collectInfoItems = <CollectInfoItem>[];

    for (var collect in collects) {
      var message = collect.message!;
      var messageType = MessageType.ofName(message.messageType.name);
      var collectInfoItem = CollectInfoItem(messageId: message.serverId!, sessionId: message.imSession!.serverId!,
          messageType: messageType, content: message.content);
      collectInfoItem.content = collect.content;
      collectInfoItems.add(collectInfoItem);
    }

    var collectReq = CollectCreateReq(collectInfoItems: collectInfoItems);

    var okListResp = await rpcBaseService.createCollect(collectReq);
    return okListResp;
  }

  void _callbackCollectServerId(Set<String> keySet, List<ImCollect> collects) {
    for(var key in keySet) {
      var keys = key.split(ImConstant.MESSAGE_SPLIT);
      var collectServerId = keys[1];
      var messageServerId = keys[0];
      for(var collect in collects) {
        if (collect.messageId == messageServerId) {
          collect.serverId = collectServerId;
          continue;
        }
      }
    }
  }
}